﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "SingleGridOffsetStrategy.h"
#include "ElementOffsetStrategyRegister.h"
#include "SingleGrid.h"
#include "IGenericElement.h"
#include "Vector3dUtils.h"
#include "IPlane.h"
#include "AlgorithmProject.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"
using namespace gcmp;

bool SingleGridOffsetStrategy::CanBeOffset(const IElement* pElement, std::wstring* explanation) const
{
    return true;
}

bool SingleGridOffsetStrategy::CanBeOffsetConnected(const IElement* pElement) const
{
    return false;
}

ElementIdArray SingleGridOffsetStrategy::GetElementsCanBeOffsetConnected(const IElement* pElement) const
{ 
    return ElementIdArray();
}

std::vector<OwnerPtr<ICurve3d>> SingleGridOffsetStrategy::GetOffsetBaseCurves(const IElement* pElement, const IPlane* pBasePlane) const
{
    std::vector<OwnerPtr<ICurve3d>> vOffsetBaseCurves;
    const IGenericElement* pGenericElement = quick_cast<const IGenericElement>(pElement);
    DBG_WARN_AND_RETURN_UNLESS(pGenericElement, vOffsetBaseCurves, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const SingleGrid* pSingleGrid = quick_cast<const SingleGrid>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_UNLESS(pSingleGrid, vOffsetBaseCurves, L"pModelLine为空",L"GDMPLab",L"2024-03-30");

    if (Vector3dUtils::IsParallel(pBasePlane->GetNormal(), Vector3d::UnitZ))
    {
        std::vector<OwnerPtr<ICurve3d>>  HorizentalCurves = pSingleGrid->GetHorizontalGridCurves();
        OwnerPtr<ICurve3d> opCurve3d = HorizentalCurves.size() > 0 ? TransferOwnership(HorizentalCurves[0]) : nullptr;
        DBG_WARN_AND_RETURN_UNLESS(opCurve3d, vOffsetBaseCurves, L"opCurve3d为空",L"GDMPLab",L"2024-03-30");
        OwnerPtr<const gcmp::ICurve3d> opResultCurve3d = AlgorithmProject::ProjectReturnCurve3d(opCurve3d.get(), pBasePlane);
        DBG_WARN_AND_RETURN_UNLESS(opResultCurve3d, vOffsetBaseCurves, L"opResultCurve3d为空",L"GDMPLab",L"2024-03-30");
        vOffsetBaseCurves.emplace_back(TransferOwnership(opResultCurve3d));
        return vOffsetBaseCurves;
    }
    else if (Vector3dUtils::IsPerpendicular(pBasePlane->GetNormal(), Vector3d::UnitZ))
    {
        OwnerPtr<ICurve3d>  VerticalCurves = pSingleGrid->GetVerticalGridCurve();
        OwnerPtr<const gcmp::ICurve3d> opResultCurve3d = AlgorithmProject::ProjectReturnCurve3d(VerticalCurves.get(), pBasePlane);
        DBG_WARN_AND_RETURN_UNLESS(opResultCurve3d, vOffsetBaseCurves, L"opResultCurve3d为空",L"GDMPLab",L"2024-03-30");
        vOffsetBaseCurves.emplace_back(TransferOwnership(opResultCurve3d));
        return vOffsetBaseCurves;
    }
    return vOffsetBaseCurves;
}

bool SingleGridOffsetStrategy::SetOffsetBaseCurves(IElement* pElement, const IPlane* pBasePlane, const std::vector<const ICurve3d *>& vCurves)
{
    if (vCurves.empty())
    {
        return false;
    }
    const ICurve3d* pCurve = vCurves[0];
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pCurve, L"pCurve为空",L"GDMPLab",L"2024-03-30");
    IGenericElement* pGenericElement = quick_cast<IGenericElement>(pElement);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    SingleGrid* pSingleGrid = quick_cast<SingleGrid>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pSingleGrid, L"pSingleGrid为空",L"GDMPLab",L"2024-03-30");
    bool Bok = false;

    if (Vector3dUtils::IsParallel(pBasePlane->GetNormal(), Vector3d::UnitZ))
    {
        OwnerPtr<const gcmp::ICurve2d> opCurve2d = AlgorithmProject::Project(pCurve, pBasePlane);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opCurve2d, L"opCurve2d为空",L"GDMPLab",L"2024-03-30");
        const std::vector<const ICurve2d*> HorizentalCurves{ opCurve2d.get() };
        auto dbgStr = HorizentalCurves[0]->GetStringForDebug();
        Bok = pSingleGrid->SetHorizontalGridCurves(HorizentalCurves);

    }
    else if (Vector3dUtils::IsPerpendicular(pBasePlane->GetNormal(), Vector3d::UnitZ))
    {
        Vector3d offsetVerticalCurveStartPoint, preOffsetVerticalCurveStartPoint;
        {
            offsetVerticalCurveStartPoint = pCurve->GetStartPoint();
            OwnerPtr<ICurve3d> preVerticalCurve = pSingleGrid->GetVerticalGridCurve();
            preOffsetVerticalCurveStartPoint = preVerticalCurve.get()->GetStartPoint();
        }
        Vector3d Position, prePosition;
        {
            Vector2d uvParameter;
            AlgorithmProject::Project(offsetVerticalCurveStartPoint, pBasePlane, uvParameter, Position);
            AlgorithmProject::Project(preOffsetVerticalCurveStartPoint, pBasePlane, uvParameter, prePosition);
        }
        Vector3d offsetDir = Position - prePosition;//平移的方向向量
        OwnerPtr<IPlane> opHorizentalPlane = IPlane::Create(Vector3d::Zero, Vector3d::UnitZ);//3dcurve的投影平面
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opHorizentalPlane, L"opHorizentalPlane为空",L"GDMPLab",L"2024-03-30");

        std::vector<OwnerPtr<ICurve3d>>  opreHorizental3dCurves = pSingleGrid->GetHorizontalGridCurves();
        std::vector<OwnerPtr<const ICurve2d>> opCastResult2dCurves;
        std::vector<const ICurve2d*> pResultCurve2ds;//轴网水平面上的投影线

        FOR_EACH(curves, opreHorizental3dCurves)
        {
            OwnerPtr<ICurve3d>horizental3dCurve;
            horizental3dCurve = TransferOwnershipCast<ICurve3d>(curves.get()->Clone());
            horizental3dCurve->Translate(offsetDir);
            opCastResult2dCurves.push_back(TransferOwnership(AlgorithmProject::Project(horizental3dCurve.get(), opHorizentalPlane.get())));
        }
        FOR_EACH(curves, opCastResult2dCurves)
        {
            pResultCurve2ds.push_back(curves.get());
        }

        Bok = pSingleGrid->SetHorizontalGridCurves(pResultCurve2ds);
    }
    return Bok;
}

REGISTER_ELEMENT_OFFSET_STRATEGY(SingleGrid, SingleGridOffsetStrategy);
